/*
* Copyright (C) Microsoft. All rights reserved.  
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not 
* use this file except in compliance with the License.  You may obtain a copy 
* of the License at http://www.apache.org/licenses/LICENSE-2.0  
* 
* THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION ANY IMPLIED 
* WARRANTIES OR CONDITIONS OF TITLE, FITNESS FOR A PARTICULAR PURPOSE, 
* MERCHANTABLITY OR NON-INFRINGEMENT. 
*
* See the Apache License, Version 2.0 for specific language governing 
* permissions and limitations under the License.
*
*/
#pragma once

#include <DXGIFormat.h>
#include <baja/graphics/graphics_types.hpp>

namespace baja { namespace graphics { namespace dx11_1 { namespace details {

inline DXGI_FORMAT toDXGI_FORMAT(const pixel_format pixelFormat)
{
    BAJA_CHECK_ARG(pixelFormat >= pixel_format::_min && pixelFormat <= pixel_format::_max);

    static DXGI_FORMAT mapping[] = 
    {
        DXGI_FORMAT_UNKNOWN,
        DXGI_FORMAT_R8G8B8A8_UNORM,
        DXGI_FORMAT_R8G8B8A8_UNORM,
        DXGI_FORMAT_R32_TYPELESS,
        DXGI_FORMAT_R32G32B32A32_FLOAT,
        DXGI_FORMAT_R32_FLOAT,
        DXGI_FORMAT_UNKNOWN,
        DXGI_FORMAT_UNKNOWN,
        DXGI_FORMAT_D32_FLOAT,
        DXGI_FORMAT_UNKNOWN,
        DXGI_FORMAT_D24_UNORM_S8_UINT,
        DXGI_FORMAT_BC1_UNORM,
        DXGI_FORMAT_BC2_UNORM,
        DXGI_FORMAT_BC2_UNORM,
        DXGI_FORMAT_BC3_UNORM,
        DXGI_FORMAT_BC3_UNORM,
        DXGI_FORMAT_FROM_FILE,
        DXGI_FORMAT_R8G8B8A8_UNORM,
        DXGI_FORMAT_B8G8R8A8_UNORM,
        DXGI_FORMAT_R8G8B8A8_UNORM,
        DXGI_FORMAT_B8G8R8A8_UNORM,
    };

    return mapping[static_cast<int32>(pixelFormat)];
}

inline D3D11_BLEND toD3D11_BLEND(const blend_state blend)
{
    BAJA_CHECK_ARG(blend >= blend_state::_min && blend <= blend_state::_max);

    static D3D11_BLEND mapping[] = 
    {
        D3D11_BLEND_ZERO,
        D3D11_BLEND_ONE,
        D3D11_BLEND_SRC_COLOR,
        D3D11_BLEND_INV_SRC_COLOR,
        D3D11_BLEND_SRC_ALPHA,
        D3D11_BLEND_INV_SRC_ALPHA,
        D3D11_BLEND_DEST_ALPHA,
        D3D11_BLEND_INV_DEST_ALPHA,
        D3D11_BLEND_DEST_COLOR,
        D3D11_BLEND_INV_DEST_COLOR,
        D3D11_BLEND_SRC_ALPHA_SAT 
    };

    return mapping[static_cast<int32>(blend)];
}

inline D3D11_BLEND_OP toD3D11_BLEND_OP(const blend_op_state blendOp)
{
    BAJA_CHECK_ARG(blendOp >= blend_op_state::_min && blendOp <= blend_op_state::_max);

    static D3D11_BLEND_OP mapping[] = 
    {
        D3D11_BLEND_OP_ADD,
        D3D11_BLEND_OP_SUBTRACT,
        D3D11_BLEND_OP_REV_SUBTRACT,
        D3D11_BLEND_OP_MIN,
        D3D11_BLEND_OP_MAX
    };

    return mapping[static_cast<int32>(blendOp)];
}

inline D3D11_DEPTH_WRITE_MASK toD3D11_DEPTH_WRITE_MASK(const enabled_state zWrite)
{
    BAJA_CHECK_ARG(zWrite >= enabled_state::_min && zWrite <= enabled_state::_max);

    static D3D11_DEPTH_WRITE_MASK mapping[] =
    {
        D3D11_DEPTH_WRITE_MASK_ZERO,
        D3D11_DEPTH_WRITE_MASK_ALL
    };

    return mapping[static_cast<int32>(zWrite)];
}

inline D3D11_COMPARISON_FUNC toD3D11_COMPARISON_FUNC(const compare_state compare)
{
    BAJA_CHECK_ARG(compare >= compare_state::_min && compare <= compare_state::_max);

    static D3D11_COMPARISON_FUNC mapping[] =
    {
        D3D11_COMPARISON_NEVER,
        D3D11_COMPARISON_LESS,
        D3D11_COMPARISON_EQUAL,
        D3D11_COMPARISON_LESS_EQUAL,
        D3D11_COMPARISON_GREATER,
        D3D11_COMPARISON_NOT_EQUAL,
        D3D11_COMPARISON_GREATER_EQUAL,
        D3D11_COMPARISON_ALWAYS
    };

    return mapping[static_cast<int32>(compare)];
}

inline D3D11_STENCIL_OP toD3D11_STENCIL_OP(const stencil_op stencilOp)
{
    BAJA_CHECK_ARG(stencilOp >= stencil_op::_min && stencilOp <= stencil_op::_max);

    static D3D11_STENCIL_OP mapping[] = 
    {
        D3D11_STENCIL_OP_KEEP,
        D3D11_STENCIL_OP_ZERO,
        D3D11_STENCIL_OP_REPLACE,
        D3D11_STENCIL_OP_INCR_SAT,
        D3D11_STENCIL_OP_DECR_SAT,
        D3D11_STENCIL_OP_INVERT,
        D3D11_STENCIL_OP_INCR,
        D3D11_STENCIL_OP_DECR
    };

    return mapping[static_cast<int32>(stencilOp)];
}

inline bool toBOOL(const enabled_state enable)
{
    BAJA_CHECK_ARG(enable >= enabled_state::_min && enable <= enabled_state::_max);

    static bool mapping[] =
    {
        false,
        true
    };

    return mapping[static_cast<int32>(enable)];
}

inline uint32 toD3D11_CLEAR_FLAG(const clear_targets clearTargets)
{
    BAJA_CHECK_ARG(clearTargets >= clear_targets::_min && clearTargets <= clear_targets::_max);

    static uint32 mapping[] = 
    {
        0,
        D3D11_CLEAR_DEPTH,
        D3D11_CLEAR_DEPTH | D3D11_CLEAR_STENCIL,
    };

    return mapping[static_cast<int32>(clearTargets)];
}

inline D3D11_PRIMITIVE_TOPOLOGY toD3D11_PRIMITIVE_TOPOLOGY(const primitive_type primitive)
{
    BAJA_CHECK_ARG(primitive >= primitive_type::_min && primitive <= primitive_type::_max);

    static D3D11_PRIMITIVE_TOPOLOGY mapping[] = 
    {
        D3D11_PRIMITIVE_TOPOLOGY_POINTLIST,
        D3D11_PRIMITIVE_TOPOLOGY_LINELIST,
        D3D11_PRIMITIVE_TOPOLOGY_LINESTRIP,
        D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST,
        D3D11_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP
    };

    return mapping[static_cast<int32>(primitive)];
}

inline D3D11_USAGE toD3D11_USAGE(const vertex_buffer_usage vbUsage)
{
    BAJA_CHECK_ARG(vbUsage >= vertex_buffer_usage::_min && vbUsage <= vertex_buffer_usage::_max);

    static D3D11_USAGE mapping[] = 
    {
        D3D11_USAGE_DEFAULT,
        D3D11_USAGE_DYNAMIC,
    };

    return mapping[static_cast<int32>(vbUsage)];
}

inline D3D11_USAGE toD3D11_USAGE(const index_buffer_usage ibUsage)
{
    BAJA_CHECK_ARG(ibUsage >= index_buffer_usage::_min && ibUsage <= index_buffer_usage::_max);

    static D3D11_USAGE mapping[] = 
    {
        D3D11_USAGE_DEFAULT,
        D3D11_USAGE_DYNAMIC,
    };

    return mapping[static_cast<int32>(ibUsage)];
}

inline D3D11_MAP toD3D11_MAP(const lock_type lockType)
{
    BAJA_CHECK_ARG(lockType >= lock_type::_min && lockType <= lock_type::_max);

    static D3D11_MAP mapping[] = 
    {
        D3D11_MAP_WRITE_DISCARD,
        D3D11_MAP_WRITE_NO_OVERWRITE,
        D3D11_MAP_READ
    };

    return mapping[static_cast<int32>(lockType)];
}

inline DXGI_FORMAT toSemanticFormat(const vertex_decl_type vertexType)
{
    BAJA_CHECK_ARG(vertexType >= vertex_decl_type::_min && vertexType <= vertex_decl_type::_max);

    static DXGI_FORMAT mapping[] = 
    {
        DXGI_FORMAT_R32_FLOAT,
        DXGI_FORMAT_R32G32_FLOAT,
        DXGI_FORMAT_R32G32B32_FLOAT,
        DXGI_FORMAT_R32G32B32A32_FLOAT,
        DXGI_FORMAT_B8G8R8A8_UNORM,
        DXGI_FORMAT_R32_UINT
    };

    return mapping[static_cast<int32>(vertexType)];
}

inline const char* toSemanticName(const vertex_decl_usage vertexUsage)
{
    BAJA_CHECK_ARG(vertexUsage >= vertex_decl_usage::_min && vertexUsage <= vertex_decl_usage::_max);

    static const char* mapping[] =
    {
        "POSITION",
        "BLENDWEIGHT",
        "BLENDINDICES",
        "NORMAL",
        "PSIZE",
        "TEXCOORD",
        "TANGENT",
        "BINORMAL",
        "TESSFACTOR",
        "SCREENPOSITION",
        "COLOR",
        "FOG",
        "DEPTH"
    };

    return mapping[static_cast<int32>(vertexUsage)];
}

// NYI:
/*
inline uint32 toMipLevels(const mipmap_load mipmapLoad)
{
    static DWORD mapping[] = 
    {
        1,
        D3DX11_DEFAULT,
        D3DX11_FROM_FILE
    };

    return mapping[static_cast<int32>(mipmapLoad)];
}

inline D3DX11_IMAGE_FILE_FORMAT toD3DX11_IMAGE_FILE_FORMAT(const file_format fileFormat)
{
    static D3DX11_IMAGE_FILE_FORMAT mapping[] = 
    {
        D3DX11_IFF_FORCE_DWORD, // unknown
        D3DX11_IFF_BMP,
        D3DX11_IFF_JPG,
        D3DX11_IFF_PNG,
        D3DX11_IFF_GIF,
        D3DX11_IFF_FORCE_DWORD, // TGA
        D3DX11_IFF_TIFF,
        D3DX11_IFF_DDS
    };
    
    return mapping[static_cast<int32>(fileFormat)];
}
*/

// The following functions convert from DX enumerations into our graphics counterparts

pixel_format
inline fromDXGI_FORMAT(const DXGI_FORMAT pixelFormat)
{
    switch (static_cast<int32>(pixelFormat))
    {
        case DXGI_FORMAT_R8G8B8A8_UNORM:
        case DXGI_FORMAT_R8G8B8A8_UNORM_SRGB:
            return pixel_format::d32BitRGBA;

        case DXGI_FORMAT_B8G8R8A8_UNORM:
        case DXGI_FORMAT_B8G8R8A8_UNORM_SRGB:
            return pixel_format::d32BitBGRA;

        case DXGI_FORMAT_D32_FLOAT:
            return pixel_format::d32;

        case DXGI_FORMAT_D24_UNORM_S8_UINT:
            return pixel_format::d24S8;

        case DXGI_FORMAT_BC1_UNORM:
        case DXGI_FORMAT_BC1_UNORM_SRGB:
            return pixel_format::dXT1;

        case DXGI_FORMAT_BC2_UNORM:
        case DXGI_FORMAT_BC2_UNORM_SRGB:
            return pixel_format::dXT3;

        case DXGI_FORMAT_BC3_UNORM:
        case DXGI_FORMAT_BC3_UNORM_SRGB:
            return pixel_format::dXT5;
    }

    // unknown format
    return pixel_format::unknown;
}

inline uint32 getBitsPerPixel(const DXGI_FORMAT pixelFormat)
{
    uint32 bpp[] = 
    {
        0,  // DXGI_FORMAT_UNKNOWN                      
        128,// DXGI_FORMAT_R32G32B32A32_TYPELESS     
        128,// DXGI_FORMAT_R32G32B32A32_FLOAT        
        128,// DXGI_FORMAT_R32G32B32A32_UINT         
        128,// DXGI_FORMAT_R32G32B32A32_SINT         
        96, // DXGI_FORMAT_R32G32B32_TYPELESS        
        96, // DXGI_FORMAT_R32G32B32_FLOAT           
        96, // DXGI_FORMAT_R32G32B32_UINT            
        96, // DXGI_FORMAT_R32G32B32_SINT            
        64, // DXGI_FORMAT_R16G16B16A16_TYPELESS     
        64, // DXGI_FORMAT_R16G16B16A16_FLOAT        
        64, // DXGI_FORMAT_R16G16B16A16_UNORM        
        64, // DXGI_FORMAT_R16G16B16A16_UINT         
        64, // DXGI_FORMAT_R16G16B16A16_SNORM        
        64, // DXGI_FORMAT_R16G16B16A16_SINT         
        64, // DXGI_FORMAT_R32G32_TYPELESS           
        64, // DXGI_FORMAT_R32G32_FLOAT              
        64, // DXGI_FORMAT_R32G32_UINT               
        64, // DXGI_FORMAT_R32G32_SINT               
        64, // DXGI_FORMAT_R32G8X24_TYPELESS         
        64, // DXGI_FORMAT_D32_FLOAT_S8X24_UINT      
        64, // DXGI_FORMAT_R32_FLOAT_X8X24_TYPELESS  
        64, // DXGI_FORMAT_X32_TYPELESS_G8X24_UINT   
        32, // DXGI_FORMAT_R10G10B10A2_TYPELESS      
        32, // DXGI_FORMAT_R10G10B10A2_UNORM         
        32, // DXGI_FORMAT_R10G10B10A2_UINT          
        32, // DXGI_FORMAT_R11G11B10_FLOAT           
        32, // DXGI_FORMAT_R8G8B8A8_TYPELESS         
        32, // DXGI_FORMAT_R8G8B8A8_UNORM            
        32, // DXGI_FORMAT_R8G8B8A8_UNORM_SRGB       
        32, // DXGI_FORMAT_R8G8B8A8_UINT             
        32, // DXGI_FORMAT_R8G8B8A8_SNORM            
        32, // DXGI_FORMAT_R8G8B8A8_SINT             
        32, // DXGI_FORMAT_R16G16_TYPELESS           
        32, // DXGI_FORMAT_R16G16_FLOAT              
        32, // DXGI_FORMAT_R16G16_UNORM              
        32, // DXGI_FORMAT_R16G16_UINT               
        32, // DXGI_FORMAT_R16G16_SNORM              
        32, // DXGI_FORMAT_R16G16_SINT               
        32, // DXGI_FORMAT_R32_TYPELESS              
        32, // DXGI_FORMAT_D32_FLOAT                 
        32, // DXGI_FORMAT_R32_FLOAT                 
        32, // DXGI_FORMAT_R32_UINT                  
        32, // DXGI_FORMAT_R32_SINT                  
        32, // DXGI_FORMAT_R24G8_TYPELESS            
        32, // DXGI_FORMAT_D24_UNORM_S8_UINT         
        32, // DXGI_FORMAT_R24_UNORM_X8_TYPELESS     
        32, // DXGI_FORMAT_X24_TYPELESS_G8_UINT      
        16, // DXGI_FORMAT_R8G8_TYPELESS             
        16, // DXGI_FORMAT_R8G8_UNORM                
        16, // DXGI_FORMAT_R8G8_UINT                 
        16, // DXGI_FORMAT_R8G8_SNORM                
        16, // DXGI_FORMAT_R8G8_SINT                 
        16, // DXGI_FORMAT_R16_TYPELESS              
        16, // DXGI_FORMAT_R16_FLOAT                 
        16, // DXGI_FORMAT_D16_UNORM                 
        16, // DXGI_FORMAT_R16_UNORM                 
        16, // DXGI_FORMAT_R16_UINT                  
        16, // DXGI_FORMAT_R16_SNORM                 
        16, // DXGI_FORMAT_R16_SINT                  
        8,  // DXGI_FORMAT_R8_TYPELESS               
        8,  // DXGI_FORMAT_R8_UNORM                  
        8,  // DXGI_FORMAT_R8_UINT                   
        8,  // DXGI_FORMAT_R8_SNORM                  
        8,  // DXGI_FORMAT_R8_SINT                   
        8,  // DXGI_FORMAT_A8_UNORM                  
        1,  // DXGI_FORMAT_R1_UNORM                  
        32, // DXGI_FORMAT_R9G9B9E5_SHAREDEXP        
        32, // DXGI_FORMAT_R8G8_B8G8_UNORM           
        32, // DXGI_FORMAT_G8R8_G8B8_UNORM           
        4,  // DXGI_FORMAT_BC1_TYPELESS              
        4,  // DXGI_FORMAT_BC1_UNORM                 
        4,  // DXGI_FORMAT_BC1_UNORM_SRGB            
        8,  // DXGI_FORMAT_BC2_TYPELESS              
        8,  // DXGI_FORMAT_BC2_UNORM                 
        8,  // DXGI_FORMAT_BC2_UNORM_SRGB            
        8,  // DXGI_FORMAT_BC3_TYPELESS              
        8,  // DXGI_FORMAT_BC3_UNORM                 
        8,  // DXGI_FORMAT_BC3_UNORM_SRGB            
        8,  // DXGI_FORMAT_BC4_TYPELESS              
        8,  // DXGI_FORMAT_BC4_UNORM                 
        8,  // DXGI_FORMAT_BC4_SNORM                 
        8,  // DXGI_FORMAT_BC5_TYPELESS              
        8,  // DXGI_FORMAT_BC5_UNORM                 
        8,  // DXGI_FORMAT_BC5_SNORM                 
        16, // DXGI_FORMAT_B5G6R5_UNORM              
        16, // DXGI_FORMAT_B5G5R5A1_UNORM            
        32, // DXGI_FORMAT_B8G8R8A8_UNORM            
        32, // DXGI_FORMAT_B8G8R8X8_UNORM            
        32, // DXGI_FORMAT_R10G10B10_XR_BIAS_A2_UNORM
        32, // DXGI_FORMAT_B8G8R8A8_TYPELESS         
        32, // DXGI_FORMAT_B8G8R8A8_UNORM_SRGB       
        32, // DXGI_FORMAT_B8G8R8X8_TYPELESS         
        32, // DXGI_FORMAT_B8G8R8X8_UNORM_SRGB       
        8,  // DXGI_FORMAT_BC6H_TYPELESS             
        8,  // DXGI_FORMAT_BC6H_UF16                 
        8,  // DXGI_FORMAT_BC6H_SF16                 
        8,  // DXGI_FORMAT_BC7_TYPELESS              
        8,  // DXGI_FORMAT_BC7_UNORM                 
        8   // DXGI_FORMAT_BC7_UNORM_SRGB            
    };

    if (pixelFormat < ARRAYSIZE(bpp))
    {
        return bpp[pixelFormat];
    }
    else
    {
        return 0;
    }
}

}}}} // namespace baja.graphics.dx11_1.details